package es.uned.etsii.si3.taller;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.sql.SQLException;
import java.util.List;

/**
 * El tipo "Cliente" almacena datos personales sobre el cliente.
 * Para todo lo demás (identificación de vehículos, etc.) se usará
 * el tipo "Usuario"
 **/
@DatabaseTable(tableName = "clientes")
public
class Cliente extends Persistente {
	public static final String ID_USUARIO_FIELD_NAME = "id_usuario";
	public static final String ID_PROVINCIA_FIELD_NAME = "id_provincia";
	public static final String DNI_FIELD_NAME = "dni";
	public static final String NOMBRE_FIELD_NAME = "nombre";
	public static final String APELLIDOS_FIELD_NAME = "apellidos";
	public static final String POBLACION_FIELD_NAME = "poblacion";
	public static final String DIRECCION_FIELD_NAME = "direccion";
	public static final String CODIGOPOSTAL_FIELD_NAME = "codigoPostal";
	public static final String TELEFONO_FIELD_NAME = "telefono";
	@DatabaseField(generatedId = true)
	int id;
	@DatabaseField(foreign = true, maxForeignAutoRefreshLevel=5, foreignAutoRefresh=true, columnName = ID_USUARIO_FIELD_NAME)
	Usuario usuario;
	@DatabaseField(width = 9, index = true)
	String dni;
	@DatabaseField(width = 30)
	String nombre;
	@DatabaseField(width = 60)
	String apellidos;
	@DatabaseField(foreign = true, maxForeignAutoRefreshLevel=5, foreignAutoRefresh=true, columnName = ID_PROVINCIA_FIELD_NAME)
	Provincia provincia;
	@DatabaseField(width = 100)
	String poblacion;
	@DatabaseField(width = 100)
	String direccion;
	@DatabaseField(width = 5)
	int codigoPostal;
	@DatabaseField(width = 20)
	String telefono;

	/**
	 * Factoría para crear nuevos clientes partiendo de un conjunto de datos,
	 * al tiempo que se crear el objeto en la base de datos
	 *
	 * @param  usuario      usuario al que está asociado esta información
	 * @param  nombre       nombre del cliente
	 * @param  apellidos    apellido(s) del cliente
	 * @param  dni          documento de identidad del cliente (9 dígitos)
	 * @param  poblacion    población de residencia (texto libre)
	 * @param  provincia    provincia de residencia (tomada de la base de datos)
	 * @param  codigoPostal
	 * @param  telefono
	 * @return          un nuevo objeto, ya guardado en la base de datos
	 * 
	 * @throws SQLException
	 */
	public
	static Cliente crear(Usuario usuario, String nombre, String apellidos,
			String dni, Provincia provincia, String poblacion,
			String direccion, int codigoPostal, String telefono)
		throws SQLException
	{
		Cliente cliente = new Cliente();

		cliente.setUsuario(usuario);
		cliente.setNombre(nombre);
		cliente.setApellidos(apellidos);
		cliente.setDni(dni);
		cliente.setPoblacion(poblacion);
		cliente.setProvincia(provincia);
		cliente.setDireccion(direccion);
		cliente.setCodigoPostal(codigoPostal);
		cliente.setTelefono(telefono);
		getClassDao(Cliente.class).create(cliente);

		return cliente;
	}

	/**
	 * Factoría para crear nuevos clientes partiendo de un objeto
	 * cliente ya existente.
	 *
	 * @param  cliente  objeto con todos los datos deseados rellenos (excepto,
	 *                  quizá el id)
	 * @return          un nuevo objeto, ya guardado en la base de datos,
	 *                  así que tendrá ID
	 * 
	 * @throws SQLException
	 */
	public
	static Cliente crear(Cliente cliente)
		throws SQLException
	{
		getClassDao(Cliente.class).create(cliente);

		return cliente;
	}

	/**
	 * Buscar un cliente partiendo del usuario al que está asociado.
	 *
	 * @param  usuario  usuario al que está asociado el cliente buscado
	 * 
	 * @return          Si el usuario está asociado a un cliente, devuelve
	 *                  un objeto que representa a dicho cliente.
	 *                  En caso contrario devuelve null
	 * 
	 * @throws SQLException
	 */
	public
	static Cliente buscarPorUsuario(Usuario usuario) throws SQLException {
		if (usuario == null)
			return null;

		List<Cliente> clientes = getClassDao(Cliente.class).queryForEq(ID_USUARIO_FIELD_NAME, usuario);

		if (clientes.size() == 0)
			return null;

		if (clientes.size() > 1) {
			// TODO: No debería suceder. ¿Qué hacer?
		}

		return clientes.get(0);
	}

	/**
	 * Busca clientes de un DNI
	 *
	 * @param  dni      DNI del cliente buscado (o clientes)
	 * @param  exacto   Si es "true", el DNI debe coincidir exactamente
	 *                  Si el "false" se hará una búsqueda parcial
	 * 
	 * @return          Devuelve una lista con los resultados de la
	 *                  búsqueda. Podría darse el caso de devolver más de un
	 *                  resultado, tanto en el caso de una búsqueda parcial
	 *                  como exacta, ya que el DNI no es estríctamente único,
	 *                  así que podría darse el caso (remoto) de devolver más
	 *                  de un resultado cuando "exacto" es true.
	 *                  La lista puede contener 0 resultados, en caso de que
	 *                  el DNI no se encuentre en la base de datos.
	 * 
	 * @throws SQLException
	 */
	public
	static List<Cliente> buscarPorDNI(String dni, boolean exacto) throws SQLException {
		return getClassDao(Cliente.class).queryForEq(DNI_FIELD_NAME, dni);
	}

	public
	Cliente() {
		// ORM Lite necesita un constructor por defecto
	}

	/**
	 * Getters y setters de los distintos parámetros
	 */
	public int       getId()           { return id; }
	public Usuario   getUsuario()      { return usuario; }
	public String    getNombre()       { return nombre; }
	public String    getApellidos()    { return apellidos; }
	public String    getDni()          { return dni; }
	public Provincia getProvincia()    { return provincia; }
	public String    getPoblacion()    { return poblacion; }
	public String    getDireccion()    { return direccion; }
	public int       getCodigoPostal() { return codigoPostal; }
	public String    getTelefono()     { return telefono; }

	public
	void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	public
	void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public
	void setApellidos(String apellidos) {
		this.apellidos = apellidos;
	}

	public
	void setDni(String dni) {
		// El DNI se guarda en mayúsculas, para asegurar que
		// las comparaciones tengan éxito
		this.dni = dni.toUpperCase();
	}

	public
	void setProvincia(Provincia provincia) {
		this.provincia = provincia;
	}

	public
	void setPoblacion(String poblacion) {
		this.poblacion = poblacion;
	}

	public
	void setDireccion(String direccion) {
		this.direccion = direccion;
	}

	public
	void setCodigoPostal(int codigoPostal) {
		this.codigoPostal = codigoPostal;
	}

	public
	void setTelefono(String telefono) {
		this.telefono = telefono;
	}
	
	/**
	 * Actualiza los datos del cliente
	 * @param nuevosDatos un objeto de tipo cliente que sustituye al actual
	 * @throws SQLException
	 */
	public
	void actualizar(Cliente nuevosDatos) throws SQLException {
		setNombre(nuevosDatos.getNombre());
		setApellidos(nuevosDatos.getApellidos());
		setDni(nuevosDatos.getDni());
		setProvincia(nuevosDatos.getProvincia());
		setPoblacion(nuevosDatos.getPoblacion());
		setDireccion(nuevosDatos.getDireccion());
		setCodigoPostal(nuevosDatos.getCodigoPostal());
		setTelefono(nuevosDatos.getTelefono());
		
		update();
	}

	@Override
	public
	String toString() {
		String cadena = new String();
		
		if (getNombre() != null) {
			cadena = cadena + getNombre() + " ";
		}
		
		if (getApellidos() != null) {
			cadena = cadena + getApellidos();
		}
		
		return cadena.trim();
	}
}